Log.print('service module: feredata');

Service.feredata = {};

// Η μέθοδος "poll" είναι αυτή που χειρίζεται ένα νέο αίτημα ενημέρωσης.
// Με την παραλαβή του αιτήματος αποστέλλεται header χαρακτηρισμού των
// δεδομένων που θα επιστραφούν (json). Αν υπάρχουν νέα δεδομένα στο
// transaction log, αποστέλλονται άμεσα. Αν το αίτημα αιτείται συνολική
// εικόνα του σκηνικού (παράμετρος "freska") αποστέλλεται το σκηνικό.
// Σε άλλη περίπτωση το αίτημα τοποθετείται στη λίστα αιτημάτων και
// θα απαντηθεί με τις νέες κινήσεις όποτε αυτές προκύψουν.
//
// Όπως προείπαμε, η μορφή των αποτελεσμάτων είναι json. Υπάρχουν τα
// εξής που μπορούν να επιστραφούν:
//
//	t:	Τραπέζια.
//
//	s:	Συνερδίες.
//
//	p:	Παίκτες.
//
//	l:	Προσκλήσεις.
//
//	x:	Σχέσεις.
//
//	k:	Κινήσεις.
//
// Επιστρέφονται επίσης και κωδικοποιημένες απαντήσεις:
//
//	-	Η συνεδρία έχει κλείσει.
//
//	=	Καμμία αλλαγή στο σκηνικό.
//
//	~	Παρωχημένο αίτημα.
//
//	?	Λανθασμένα αποτελέσματα.

Service.feredata.poll = function(nodereq) {
	// Αποστέλλεται άμεσα η αρχή της απάντησης, ήτοι τα header
	// data.

	nodereq.header('json');

	// Ελέγχεται η εγκυρότητα του αιτήματος όσον αφορά στην
	// ταυτότητα του αποστολέα.

	if (nodereq.isvoli(',"-":0')) return;

	// Κλείνουμε τυχόν προηγούμενο αίτημα ενημέρωσης της ίδιας
	// συνεδρίας, που ίσως βρίσκεται σε αναμονή, αποστέλλοντας
	// κωδικό παρωχημένου αιτήματος.

	if (nodereq.sinedria.isFeredata()) nodereq.sinedria.feredataClose(',"~":0');

	// Αν υπάρχει η παράμετρος "freska" σημαίνει ότι το αίτημα αφορά σε
	// αποστολή όλων των σκηνικών δεδομένων και όχι μόνο των αλλαγών,
	// οπότε αποστέλλουμε άμεσα το σκηνικό, αλλιώς τοποθετούμε το αίτημα
	// σε αναμονή και αν χρειάζεται προχωρούμε σε άμεση ενημέρωση.

	if (nodereq.url.hasOwnProperty('freska')) Service.feredata.freska(nodereq);
	else nodereq.sinedria.feredataAnamoni(nodereq).enimerosi();
}

Service.feredata.freska = function(nodereq) {
	var lk, pk;

	// Πριν αρχίσουμε την αποστολή των σκηνικών δεδομένων,
	// κρατάμε το τρέχον μέγεθος του transaction log ώστε
	// να μπορούμε να ελέγξουμε αν στην πορεία έχουμε νέες
	// κινήσεις.

	lk = Skiniko.kinisi.length;

	Service.feredata.trapezi(nodereq);
	Service.feredata.sinedria(nodereq);
	Service.feredata.pektis(nodereq);
	Service.feredata.prosklisi(nodereq);
	Service.feredata.sxesi(nodereq);
	Service.feredata.sizitisi(nodereq, Skiniko.sizitisi, 'z');
	Service.feredata.tsoxa(nodereq);

	// Αν έχει αλλάξει το μέγεθος του transaction log στο
	// ενδιάμεσο διάστημα, τότε έχουμε σοβαρό πρόβλημα.

	if (lk != Skiniko.kinisi.length) {
		console.log('WARNING: transaction log length: ' + lk + ' <> ' + Skiniko.kinisi.length);
		nodereq.write(',"?": "Transaction log infection"');
	}

	// Κρατάμε το τρέχον μέγεθος του transaction log ώστε την
	// επόμενη φορά να αποστείλουμε μόνο τις νέες κινήσεις.

	nodereq.sinedria.kinisi = lk;
	nodereq.end();
}

// Το array "izepart" χρησιμοποιείται για ταξινόμηση των τραπεζιών ώστε
// να αποσταλούν τραπέζια και προσκλήσεις με τη σωστή σειρά.

Service.feredata.izepart = [];

// Η μέθοδος "trapezi" στέλνει το array των τραπεζιών. Μέσα στα τραπέζια
// περιλαμβάνονται οι παράμετροι τραπεζιού, οι προσκλήσεις, οι διανομές
// και οι ενέργειες της τελευταίας διανομής, ενώ ΔΕΝ περιλαμβάνονται οι
// θεατές οι οποίοι θα αποσταλούν σε δική τους λίστα.

Service.feredata.trapezi = function(nodereq) {
	Service.feredata.izepart = [];
	Skiniko.trapeziWalk(function(kodikos) {
		Service.feredata.izepart.push(kodikos);
	});
	Service.feredata.izepart.sort(function(a, b) { return a - b; });

	var x1 = ',\nt:[\n';
	var x2 = '';
	for (var i = 0; i < Service.feredata.izepart.length; i++) {
		var trapezi = Skiniko.isTrapezi(Service.feredata.izepart[i]);
		if (!trapezi) continue;

		nodereq.write(x1 + '\t' + trapezi.feredataFormat(nodereq.sinedria));
		x1 = ',\n';
		x2 = '\n]\n';
	}
	nodereq.write(x2);
}

Service.feredata.sinedria = function(nodereq) {
	var x1 = ',\ns:[\n';
	var x2 = '';
	Skiniko.sinedriaWalk(function(pektis, sinedria) {
		nodereq.write(x1 + '\t' + sinedria.feredataFormat());
		x1 = ',\n';
		x2 = '\n]\n';
	});
	nodereq.write(x2);
}

Service.feredata.pektis = function(nodereq) {
	var x1 = ',\np:{';
	var x2 = '';
	Skiniko.pektisWalk(function(login, pektis) {
		nodereq.write(x1 + '\t' + pektis.feredataFormat(nodereq.sinedria.pektis));
		x1 = ',\n';
		x2 = '\n}\n';
	});
	nodereq.write(x2);
}

// Η μέθοδος "prosklisi" στέλνει τις προσκλήσεις σε δικό τους κεφάλαιο.
// Αποστέλλονται μόνο προσκλήσεις που εμπλέκουν τον παίκτη του αιτούντος
// client.

Service.feredata.prosklisi = function(nodereq) {
	var l = [];
	Skiniko.trapeziWalk(function(kodikos, trapezi) {
		globals.walk(trapezi.prosklisi, function(kodikos, prosklisi) {
			if ((prosklisi.apo == nodereq.sinedria.pektis) ||
				(prosklisi.pros == nodereq.sinedria.pektis)) l.push(prosklisi);
		});
	});
	if (!l.length) return;

	l.sort(function(p1, p2) {
		return p1.kodikos - p2.kodikos;
	});
		
	var x1 = ',\nl:[\n';
	var x2 = '';
	for (var i = 0; i < l.length; i++) {
		x = x1 + '\t{k:' + parseInt(l[i].kodikos);
		x += ',t:' + parseInt(l[i].trapezi);
		if (l[i].apo != nodereq.sinedria.pektis) x += ',a:' + globals.json(l[i].apo);
		if (l[i].pros != l[i].apo) x += ',p:' + globals.json(l[i].pros);
		x += ',e:' + parseInt(l[i].epidosi);
		x += '}';
		nodereq.write(x);
		x1 = ',\n';
		x2 = '\n]\n';
	}
	nodereq.write(x2);
}

// Η μέθοδος "sxesi" στέλνει τις σχέσεις σε δικό τους κεφάλαιο.
// Αποστέλλονται μόνο σχέσεις που εμπλέκουν τον παίκτη του αιτούντος
// client.

Service.feredata.sxesi = function(nodereq) {
	var x1 = ',\nx:{\n';
	var x2 = '';
	globals.walk(nodereq.pektis.fetchProp('sxesi'), function(sxetizomenos, sxesi) {
		x = x1 + '\t' + globals.json(sxetizomenos) + ':' + globals.json(sxesi.sxesi);
		nodereq.write(x);
		x1 = ',\n';
		x2 = '\n}\n';
	});
	nodereq.write(x2);
}

Service.feredata.sizitisi = function(nodereq, sizitisi, tk) {
	var x1, x2, i0, i;

	x1 = ',\n' + tk + ':[\n';
	x2 = '';

	// Δεν θα στείλουμε ολόκληρη τη συζήτηση, αλλά μόνο τις τελευταίες
	// γραμμές.

	i0 = sizitisi.length - Prefadoros.maxSxolia;
	if (i0 < 0) i0 = 0;

	for (i = i0; i < sizitisi.length; i++) {
		nodereq.write(x1 + '\t{p:' + globals.json(sizitisi[i].pektis) +
			',k:' + globals.json(sizitisi[i].kimeno) +
			',w:' + sizitisi[i].pote + '}');
		x1 = ',\n';
		x2 = '\n]\n';
	}
	nodereq.write(x2);
}

Service.feredata.energia = function(nodereq) {
	var trapezi, dianomi, energia, x1, x2, i0, i;

	if (!nodereq.trapezi) return;
	trapezi = nodereq.trapezi;
	if (trapezi.oxiDianomi()) return;
	dianomi = trapezi.dianomi[trapezi.dianomi.length - 1];
	if (!dianomi.energia.length) return;
	energia = dianomi.energia;

	x1 = ',\nE:[\n';
	x2 = '';

	for (i = 0; i < energia.length; i++) {
		nodereq.write(x1 + '\t' + energia[i].feredataFormat(nodereq.sinedria));
		x1 = ',\n';
		x2 = '\n]\n';
	}
	nodereq.write(x2);
}

// Η μέθοδος "tsoxa" στέλνει πληροφορίες που αφορούν στο τραπέζι του αιτούντος,
// εφόσον ο αιτών βρίσκεται σε κάποιο τραπέζι.

Service.feredata.tsoxa = function(nodereq) {
	if (!nodereq.trapezi) return;
	Service.feredata.sizitisi(nodereq, nodereq.trapezi.sizitisi, 'Z');
	Service.feredata.energia(nodereq);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η property "timeout" χρησιμοποιείται στην αυτόματη επαναδρομολόγηση
// αιτημάτων ενημέρωσης. Αν κάποιο αίτημα δεν στείλει δεδομένα για το
// εν λόγω χρονικό διάστημα (seconds), επιστρέφεται απάντηση μη αλλαγής
// οπότε ο client δρομολογεί νέο αίτημα. Η τιμή θα υπολογιστεί κατά το
// στήσιμο των περιπόλων.

Service.feredata.timeout = 0;

// Η μέθοδος "check" καλείται σε τακτά χρονικά διαστήματα και σκοπό έχει
// τον έλεγχο των ανοικτών αιτημάτων παραλαβής δεδομένων όσον αφορά στο
// χρόνο αναμονής. Αν βρεθούν αιτήματα που παραμένουν σε αναμονή για μεγάλο
// χρονικό διάστημα, κλείνουν και δρομολογούνται νέα αιτήματα από τους
// αντίστοιχους clients.

Service.feredata.check = function() {
console.log('Service.feredata: check (' + globals.ora() + ')');
	var tora = globals.toraServer();
	Skiniko.sinedriaWalk(function(pektis, sinedria) {
		if (sinedria.oxiFeredata()) return;
		if (tora - sinedria.poll < Service.feredata.timeout) return;
console.log('Service.feredata timeout: ' + pektis);
		sinedria.feredataClose(',"=":0');
	});
}
